/*
 * @[H]:  Copyright (c) 2021 Phytium Information Technology, Inc. 
 * 
 *  SPDX-License-Identifier: Apache-2.0. 
 * 
 * @Date: 2021-07-16 15:24:50
 * @LastEditTime: 2021-09-04 22:37:04
 * @Description:  Description of file
 * @Modify History: 
 * * * Ver   Who        Date         Changes
 * * ----- ------     --------    --------------------------------------
 */
#include "smp.h"
#include "sdkconfig.h"
#include "ft_types.h"




#ifdef CONFIG_TARGET_ARMV8_AARCH32


typedef union
{
    unsigned long slock;
    struct ArchTicket
    {
        unsigned short owner;
        unsigned short next;
    } Tickets;
} FCpuLock;


#ifdef CONFIG_SPIN_MEM
FCpuLock *_lock = (FCpuLock *)CONFIG_SPIN_MEM;
#else
FCpuLock _static_lock ;
FCpuLock *_lock = &_static_lock ;
#endif

void SpinLockInit(unsigned long global_addr)
{
    _lock = (FCpuLock *)global_addr; 
    _lock->slock = 0;
}

void SpinLock(void)
{
    u32 tmp;
    u32 new_val;
    FCpuLock lock_val;

    __asm__ __volatile__(
        "pld [%0]" ::"r"(&_lock->slock));

    __asm__ __volatile__(
        "1: ldrex   %0, [%3]\n"
        "   add %1, %0, %4\n"
        "   strex   %2, %1, [%3]\n"
        "   teq %2, #0\n"
        "   bne 1b"
        : "=&r"(lock_val), "=&r"(new_val), "=&r"(tmp)
        : "r"(&_lock->slock), "I"(1 << 16)
        : "cc");

    while (lock_val.Tickets.next != lock_val.Tickets.owner)
    {
        __asm__ __volatile__("wfe" ::
                                 : "memory");
        lock_val.Tickets.owner = *(volatile unsigned short *)(&_lock->Tickets.owner);
    }

    __asm__ volatile("dmb" ::
                         : "memory");
}

void SpinUnlock(void)
{
    __asm__ volatile("dmb" ::
                         : "memory");
    _lock->Tickets.owner++;
    __asm__ volatile("dsb ishst\nsev" ::
                         : "memory");
}

#else


#ifdef CONFIG_SPIN_MEM
fsize_t *_lock = (fsize_t *)CONFIG_SPIN_MEM;
#else
fsize_t _static_lock ;
fsize_t *_lock = &_static_lock ;
#endif

extern void ArchSpinLock(fsize_t *lock);
extern void ArchSpinUnlock(fsize_t *lock); 

void SpinLockInit(unsigned long global_addr)
{
    _lock = (fsize_t *)global_addr; 
    *_lock = 0 ;
}

void SpinLock(void)
{
    ArchSpinLock(_lock) ;
}

void SpinUnlock(void)
{
    ArchSpinUnlock(_lock) ;
}


#endif